# -*- coding: utf-8 -*-
# 主要代码：
import pdfplumber
import re
from pdfplumber import pdf


def get_data_from_pdf(pdf_file):
    """
    获取pdf文件中的招标公告相关数据
    :param pdf_file:
    :return:
    """
    # 1.首先确定pdf文件中招标公告的页码
    pub_info_start_page, pub_info_end_page = -1, -1
    # 招标公告信息合并结果
    pub_info_combine = ""
    # 判断是否是招标公告信息
    pub_record = False
    # 各种判断是否为招标公告信息的pattern
    pattern_pub = re.compile(r'第一章\s+招标公告')
    pattern_condi = re.compile(r'招标条件')
    pattern_category = re.compile(r'目\s+录')
    pattern_tender_know = re.compile(r'章\s+投标人须知')
    pattern_tender_table = re.compile(r'投标人须知前附表')
    # 打开pdf文件，进行分析
    # 返回[(title,body)]
    title_body_list = []
    with pdfplumber.open(pdf_file) as pdf:
        for i, page in enumerate(pdf.pages):
            text = page.extract_text_simple()
            if pattern_tender_know.search(text) and pattern_tender_table.search(text) and not pattern_category.search(
                    text):
                print(f"pub info start end page {i - 1}")
                pub_info_end_page = i - 1
                # 招标公告信息已结束(在前一页已经结束)
                break
            if pattern_pub.search(text) and pattern_condi.search(text) and not pattern_category.search(text):
                # 招标公告开始页
                print(f"pub info start on page {i + 1}")
                pub_info_start_page = i
                pub_record = True
            if pub_record:
                pub_info_combine += get_text_info(page)
        print(pub_info_start_page, pub_info_end_page)
        print(pub_info_combine)
        project_no, project_name = get_project_no_name(pub_info_combine)
        if not project_no or not project_name:
            # TODO 待优化页面提示
            raise RuntimeError("未找到项目编号或者项目名称")
        regex_pattern = r'\s(?=\d+[\.、]\D+\n)'
        paragraphs = split_paragraphs(pub_info_combine, regex_pattern)
        if paragraphs:
            # 从(1,len(paragraphs))进行切分
            title_body_list = [get_para_title_body(paragraphs[i]) for i in range(1, len(paragraphs))]
    return title_body_list, project_name, project_no


def get_tender_need_info(pdf_file):
    pattern_category = re.compile(r'目\s+录')
    pattern_tender_table_start = re.compile(r'投标人须知前附表\s?\n')
    pattern_tender_table_end = re.compile(r'\d+[\\.、]总则')
    tender_to_know_start_page, tender_to_know_end_page = -1, -1
    table_info_list = []
    table_info_text = ""
    table_record = False
    with pdfplumber.open(pdf_file) as pdf:
        # pdf.to_dict()
        for i, page in enumerate(pdf.pages):
            text = page.extract_text()
            if pattern_tender_table_end.search(text) and not pattern_category.search(text):
                print(f"tender table end page {i}")
                tender_to_know_end_page = i - 1
                table_record = False
                break
            if pattern_tender_table_start.search(text) and not pattern_category.search(text):
                print(f"tender table start page {i + 1}")
                tender_to_know_start_page = i
                table_record = True
            if table_record:
                table_info = page.extract_table()
                if table_info:
                    table_info_list.extend(table_info)
                table_info_text += text
    print(f'table_info_list={table_info_list}')
    print(f'table_info_text={table_info_text}')





def get_project_no_name(pub_info_combine):
    """
    提取项目编号和项目名称
    :param pub_info_combine:
    :return:
    """
    project_no_pattern = re.compile(r"[招项]\s*[标目]\s*编\s*号\s*：\s*([A-Z0-9]+)")
    project_name_pattern = re.compile(r"[招项]\s*[标目]\s*名\s*称\s*：\s*(.*?)\n")
    # 全局检索出项目编号和项目名称
    project_no_match = project_no_pattern.search(pub_info_combine)
    project_name_match = project_name_pattern.search(pub_info_combine)
    print("=" * 50)
    # 项目编号
    project_no = ""
    # 项目名称
    project_name = ""
    if project_no_match:
        project_no = project_no_match.group(1)
    if project_name_match:
        project_name = project_name_match.group(1)
    return project_no, project_name


def get_text_info(page: pdf.Page):
    """
    todo 优化跨页表格情况，待实验
    获取文本信息(将文本信息和表格信息分开)
    :param page: 需要分析的pdf.Page
    :return:
    """
    # 1.提取所有表格数据
    tables = page.find_tables()
    box_list = []
    if tables:
        # 获取所有tables的bbox
        box_list = [table.bbox for table in tables]
    # 提取表格内容
    table_content_list = [page.within_bbox(bbox) for bbox in box_list]
    print(f'table_content_list= {[table_content.extract_table() for table_content in table_content_list]}')
    # 2.提取表格以外的文本内容
    table_bbox_list = [(box[1], box[3]) for box in box_list]
    new_chars = filter(lambda x: district_object_not_in_table(x, table_bbox_list), page.objects.get('char', []))
    page.objects.update({'char': list(new_chars)})
    out_of_tables_text = page._get_textmap().as_string
    # 去除分页数据
    page_pattern = re.compile(r"(第*\d+\s*页$)|(\s*\d+$)")
    # 是否包含页码信息
    match_page = page_pattern.search(out_of_tables_text)
    if out_of_tables_text and match_page:
        # 去除页码数据
        out_of_tables_text = out_of_tables_text[:-len(match_page.group())]
    # 3.文本内容 + 拼装表格
    # todo 待优化，暂时只简单处理
    table_content_str = ""
    if table_content_list:
        for table_content in table_content_list:
            table_content_str += str(table_content.extract_table())
        # 简单处理，判断是否是"标段划分招标内容内容:"
        bid_pattern = re.compile(r"[\d.、]+\s*.*?标段[\u4e00-\u9fff]*：\s*\n")
        match_bid = bid_pattern.search(out_of_tables_text)
        if match_bid:
            origin_text = match_bid.group()
            to_replace_text = origin_text + table_content_str + "\n"
            out_of_tables_text = out_of_tables_text.replace(origin_text, to_replace_text)
    return out_of_tables_text + "\n"


def district_object_not_in_table(obj, table_bbox_list):
    # 只获取文本char的内容
    if distinguish_char_out_all_box(obj, table_bbox_list):
        return True
    return False


def distinguish_char_out_all_box(obj_char, top_bottom_list):
    """
    判断字符是否在所有框的外部
    :param obj_char:
    :param top_bottom_list:
    :return:
    """
    return all(distinguish_char_out_box(obj_char, top, bottom) for top, bottom in top_bottom_list)


def distinguish_char_out_box(obj_char, top, bottom):
    """
    判断字符是否在框的外部
    :param obj_char:
    :param top:
    :param bottom:
    :return:
    """
    if obj_char['bottom'] < top or obj_char['top'] > bottom:
        return True
    return False


def split_paragraphs(text, regex_pattern):
    """ 使用正则表达式分割文本为段落 """
    return re.split(regex_pattern, text.strip())


def get_para_title_body(paragraph):
    """
    获取标题和正文
    :param paragraph:
    :return:
    """
    # 每一段内容，去除段落开头的的数字和末尾的换行符
    para = re.sub(r'^[\d!、.\n ]+|[!.\n ]+$', '', paragraph).strip()
    chinese_chars = []
    para_nns = para.split('\n')
    # 标题中中文
    title = para_nns[0]
    # 标题中正文部分
    body_text = '\n'.join(para_nns[1:])
    return title, body_text


if __name__ == '__main__':
    # get_data_from_pdf("../data/招标文件正文(1).pdf")
    # pattern = re.compile(r'^[^\u4e00-\u9fff]+|[^\u4e00-\u9fff]+$')
    # mx = pattern.sub('', "1.1.我是abc")
    # print(mx)
    get_tender_need_info("../data/招标文件正文(1).pdf")
